此範例參考solidity example其中一個,為Auction合約的升級版,場景設定在不知展示的投標物價值為多少,每個參與者可以針對有興趣的投標物出價並將錢放進合約
當投標時間結束後才會開始依照每個參與者的投標價格來判定,誰出價最高並且最有機會得標,其中出價低於標準,會將錢退還給參與者
pragma solidity^0.4.25;
contract BlindAuction{
struct Bid{
bytes32 bidHash;
uint deposit;
}
address public beneficiary; // 受益人
uint public biddingEndTime; // 投標結束時間
uint public revealEndTime; // 展示結束時間
bool public ended; //合約結束狀態
address public highestBidder; //最高出價者
uint public highestBid; //最高出價
mapping (address => Bid[]) bids; //參與者投標多個項目
mapping (address => uint ) pendingReturn; // record all bid of bidder
event AuctionEnd(address winner,uint highestBid);
modifier onlyBefore(uint _time){ require(now < _time); _;}
modifier onlyAfter(uint _time){ require(now > _time); _;}
//參數輸入受益人、投標時間、展示時間
constructor(
address _beneficiary,
uint _biddingTime,
uint _revealTime
) public {
beneficiary =_beneficiary;
biddingEndTime = now + _biddingTime;
revealEndTime = biddingEndTime + _revealTime;
}
//投標出價的function,參與者要在投標結束時間前執行
//bidHash = keccak256(abi.encodePacked(value,fake,key));
function bid(
bytes32 _bidHash
)
public
payable
onlyBefore(biddingEndTime)
{
bids[msg.sender].push(
Bid(
_bidHash,
msg.value
)
);
}
//輸入展示項目的資料,只限定在投標時間後,展示時間前可以呼叫function
//將目前展示的所有項目和參與者投標的項目做比對,出價沒有符合標準會退錢給參與者,出價最高將會做好紀錄
function reveal(
uint[] _value,
bool[] _fake,
bytes32[] _secret
)
public
onlyAfter(biddingEndTime)
onlyBefore(revealEndTime)
{
// 計算msg.sender投標多少個項目
uint length = bids[msg.sender].length;
uint refund;
//判斷展示的數量和msg.sender投標的數量相符合
require(_value.length == length,"value length isn't match");
require(_fake.length == length,"fake length isn't match");
require(_secret.length == length,"secret length isn't match");
for(uint8 i = 0; i < length ; i++){
Bid storage bid_ = bids[msg.sender][i];
(uint value, bool fake, bytes32 secret) = (_value[i],_fake[i],_secret[i]);
//確認第i個投標項目的hash是不是和展示項目的hash一致
if(bid_.bidHash == keccak256(abi.encodePacked(value,fake,secret))){
continue;
}
//增加msg.sender退錢額度
refund += bid_.deposit;
//確認fake為false 或是出價高於本身價值
if(!fake && bid_.deposit >= value){
//如果為true代表為最高出價
if(placeBid(msg.sender,value)){
/
refund -= value;
}
//將賣家投標的項目hash清除,表示已經執行過
bid_.bidHash = bytes32(0);
}
//將投標項目沒有達到標準的出價退錢給參與者
msg.sender.transfer(refund);
}
}
function placeBid(address _bidder,uint _value) internal returns(bool success){
// 確認投標的出價大於目前最高出價
if(_value <= highestBid){
return false;
}
// 確認目前最高投標者address是否為有效address
if(highestBidder != 0){
//因為有更高出價的投標者, 所以會退錢給目前最高投標者
pendingReturn[highestBidder] += highestBid;
}
//設定最新的出價及投標者
highestBid = _value;
highestBidder = _bidder;
return true;
}
//提款
function withdraw() public {
uint amount = pendingReturn[msg.sender];
//確認msg.sender 的pending有無超過0
if(amount > 0 ){
//初始化pending return 的 value
pendingReturn[msg.sender] = 0;
msg.sender.transfer(amount);
}
}
//拍賣結束受益人拿回價格,只能在拍賣時間結束、合約狀態還沒終止後執行
function auctionEnded() public onlyAfter(revealEndTime){
//確認拍賣合約狀態
require(!ended);
//teigger event to log winner address and highestBid
emit AuctionEnd(highestBidder,highestBid);
ended = true;
beneficiary.transfer(highestBid);
}
}
(待補)